/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2019, Main, China, Mrtutu.
**                           All Rights Reserved
**
**                                By Mrtutu
**                           Blog: www.mrtutu.cn
**
**----------------------------------文件信息------------------------------------
** @flie    : oled.c
** @auther  : Mrtutu
** @date    : 2019-06-10
** @describe:
**
**----------------------------------版本信息------------------------------------
** 版本代号: V0.1
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/

#include "oled.h"
#include "oledfont.h"



/* 下面2个宏任选 1个; 表示显示方向 */
//#define DIR_NORMAL			/* 此行表示正常显示方向 */
#define DIR_180				/* 此行表示翻转180度 */

/* 12864 OLED的显存镜像，占用1K字节. 共8行，每行128像素 */
static uint8_t s_ucGRAM[8][128];

/* 为了避免刷屏拉幕感太强，引入刷屏标志。
0 表示显示函数只改写缓冲区，不写屏。1 表示直接写屏（同时写缓冲区） */
static uint8_t s_ucUpdateEn = 1;







/**********************************IIC 驱动*************************************/
//SCL -- PB12
//SDA -- PB13
void IIC_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);	  //初始化GPIOD3,6
    GPIO_SetBits(GPIOB, GPIO_Pin_12 | GPIO_Pin_13);

    IIC_SCL = 1;
    IIC_SDA = 1;
}


//产生IIC起始信号
void IIC_Start(void)
{
    SDA_OUT();     //sda线输出
    IIC_SDA = 1;
    IIC_SCL = 1;
    delay_us(1);
    IIC_SDA = 0;   //START:when CLK is high,DATA change form high to low
    delay_us(1);
    IIC_SCL = 0;   //钳住I2C总线，准备发送或接收数据
}


//产生IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT();//sda线输出
    IIC_SCL = 0;
    IIC_SDA = 0; //STOP:when CLK is high DATA change form low to high
    delay_us(1);
    IIC_SCL = 1;
    IIC_SDA = 1; //发送I2C总线结束信号
    delay_us(1);
}


//等待应答信号到来
//返回值：1，接收应答失败
//        0，接收应答成功

u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime = 0;
    SDA_IN();      //SDA设置为输入
    IIC_SDA = 1;
    delay_us(1);
    IIC_SCL = 1;
    delay_us(1);

    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime > 250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL = 0; //时钟输出0
    return 0;
}

//产生ACK应答
void IIC_Ack(void)
{
    IIC_SCL = 0;
    SDA_OUT();
    IIC_SDA = 0;
    delay_us(1);
    IIC_SCL = 1;
    delay_us(1);
    IIC_SCL = 0;
}

//不产生ACK应答
void IIC_NAck(void)
{
    IIC_SCL = 0;
    SDA_OUT();
    IIC_SDA = 1;
    delay_us(2);
    IIC_SCL = 1;
    delay_us(2);
    IIC_SCL = 0;
}
//IIC发送一个字节
//返回从机有无应答
//1，有应答
//0，无应答
void IIC_Send_Byte(u8 txd)
{
    u8 t;
    SDA_OUT();
    IIC_SCL = 0; //拉低时钟开始数据传输

    for(t = 0; t < 8; t++)
    {
        if((txd & 0x80) >> 7)
            IIC_SDA = 1;
        else
            IIC_SDA = 0;
        txd <<= 1;
        delay_us(1);
        IIC_SCL = 1;
        delay_us(1);
        IIC_SCL = 0;
        delay_us(1);
    }
}



//读1个字节，ack=1时，发送ACK，ack=0，发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i, receive = 0;
    SDA_IN();//SDA设置为输入
    for(i = 0; i < 8; i++)
    {
        IIC_SCL = 0;
        delay_us(1);
        IIC_SCL = 1;
        receive <<= 1;

        if(READ_SDA)receive++;
        delay_us(1);
    }
    if(!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK
    return receive;
}





///**********************************************
//// 通过I2C总线写一个字节
//**********************************************/
void Write_IIC_Byte(unsigned char IIC_Byte)
{
    unsigned char i;
    for(i = 0; i < 8; i++)
    {
        if(IIC_Byte & 0x80)
            IIC_SDA = 1;
        else
            IIC_SDA = 0;
        IIC_SCL = 1;
        delay_us(1);
        IIC_SCL = 0;
        IIC_Byte <<= 1;
    }
    //IIC_SDA = 1; //原程序这里有一个拉高SDA，根据OLED的DATASHEET，此句必须去掉。
    IIC_SCL = 1;
    delay_us(1);
    IIC_SCL = 0;
}



/**********************************IIC 驱动*************************************/


/**********************************OLED 驱动*************************************/

//static uint8_t s_ucGRAM[8][128];
void OLED_ClearBuf(void)
{
    u8 i;//行
    u8 j;//列
    for(i = 0; i < 8; i++)
    {
        for(j = 0; j < 128; j++)
        {
            s_ucGRAM[i][j] = 0;
        }
    }
    
}



/*********************OLED写数据************************************/
void OLED_WrDat(unsigned char IIC_Data)
{
    IIC_Start();
    IIC_Send_Byte(0x78);			//D/C#=0; R/W#=0
    IIC_Wait_Ack();
    IIC_Send_Byte(0x40);			//write data
    IIC_Wait_Ack();
    IIC_Send_Byte(IIC_Data);
    IIC_Wait_Ack();
    IIC_Stop();
}


/*********************OLED写命令************************************/
void OLED_WrCmd(unsigned char IIC_Command)
{
    IIC_Start();
    IIC_Send_Byte(0x78);            //Slave address,SA0=0
    if(IIC_Wait_Ack())
    {
        while(1);
    }
    IIC_Send_Byte(0x00);			//write command
    IIC_Wait_Ack();
    IIC_Send_Byte(IIC_Command);
    IIC_Wait_Ack();
    IIC_Stop();
}



//开启OLED显示
void OLED_Display_On(void)
{
    OLED_WrCmd(0X8D);  //SET DCDC命令
    OLED_WrCmd(0X14);  //DCDC ON
    OLED_WrCmd(0XAF);  //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
    OLED_WrCmd(0X8D);  //SET DCDC命令
    OLED_WrCmd(0X10);  //DCDC OFF
    OLED_WrCmd(0XAE);  //DISPLAY OFF
}


/*
*********************************************************************************************************
*	函 数 名: OLED_SetDir
*	功能说明: 设置显示方向
*	形    参: _ucDir = 0 表示正常方向，1表示翻转180度
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_SetDir(uint8_t _ucDir)
{
    if(_ucDir == 0)
    {
        OLED_WrCmd(0xA0);	/* A0 ：列地址0映射到SEG0; A1 ：列地址127映射到SEG0 */
        OLED_WrCmd(0xC0);	/* C0 ：正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
    }
    else
    {
        OLED_WrCmd(0xA1);	/* A0 ：列地址0映射到SEG0; A1 ：列地址127映射到SEG0 */
        OLED_WrCmd(0xC8);	/* C0 ：正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
    }
}


/*
*********************************************************************************************************
*	函 数 名: OLED_SetContrast
*	功能说明: 设置对比度
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_SetContrast(uint8_t ucValue)
{
    OLED_WrCmd(0x81);	/* 设置对比度命令(双字节命令），第1个字节是命令，第2个字节是对比度参数0-255 */
    OLED_WrCmd(ucValue);	/* 设置对比度参数,缺省CF */
}


/*
*********************************************************************************************************
*	函 数 名: OLED_StartDraw
*	功能说明: 开始绘图。以后绘图函数只改写缓冲区，不改写面板显存
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_StartDraw(void)
{
    s_ucUpdateEn = 0;
    OLED_ClearBuf();
}


/*
*********************************************************************************************************
*	函 数 名: OLED_EndDraw
*	功能说明: 结束绘图。缓冲区的数据刷新到面板显存。 OLED_StartDraw() 和 OLED_EndDraw() 必须成对使用
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_EndDraw(void)
{
    s_ucUpdateEn = 1;
    OLED_BufToPanel();
}


/*
*********************************************************************************************************
*	函 数 名: OLED_ClrScr
*	功能说明: 清屏
*	形    参:  _ucMode : 0 表示全黑； 0xFF表示全亮
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_ClrScr(uint8_t _ucMode)
{
    uint8_t i, j;

    for(i = 0 ; i < 8; i++)
    {
        for(j = 0 ; j < 128; j++)
        {
            s_ucGRAM[i][j] = _ucMode;
        }
    }

    if(s_ucUpdateEn == 1)
    {
        OLED_BufToPanel();
    }
}


/*
*********************************************************************************************************
*	函 数 名: OLED_BufToPanel
*	功能说明: 将缓冲区中的点阵数据写入面板
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
static void OLED_BufToPanel(void)
{
    uint8_t i, j;

    for(i = 0 ; i < 8; i++)
    {
        OLED_WrCmd(0xB0 + i);	/* 设置页地址（0~7） */
        OLED_WrCmd(0x00);		/* 设置列地址的低地址 */
        OLED_WrCmd(0x10);		/* 设置列地址的高地址 */

        for(j = 0 ; j < 128; j++)
        {
            OLED_WrDat(s_ucGRAM[i][j]);
        }
    }
}


/*
*********************************************************************************************************
*	函 数 名: OLED_PutPixel
*	功能说明: 画1个像素
*	形    参:
*			_usX,_usY : 像素坐标
*			_ucColor  ：像素颜色
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_PutPixel(uint16_t _usX, uint16_t _usY, uint8_t _ucColor)
{
    uint8_t ucValue;
    uint8_t ucPageAddr;
    uint8_t ucColAddr;

    const uint8_t aOrTab[8]  = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
    const uint8_t aAndTab[8] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};

    ucPageAddr = _usY / 8;
    ucColAddr = _usX;

    ucValue = s_ucGRAM[ucPageAddr][ucColAddr];
    if(_ucColor == 0)
    {
        ucValue &= aAndTab[_usY % 8];
    }
    else
    {
        ucValue |= aOrTab[_usY % 8];
    }
    s_ucGRAM[ucPageAddr][ucColAddr] = ucValue;

    if(s_ucUpdateEn == 1)
    {
        OLED_WrCmd(0xB0 + ucPageAddr);					/* 设置页地址（0~7） */
        OLED_WrCmd(0x00 + (ucColAddr & 0x0F));			/* 设置列地址的低地址 */
        OLED_WrCmd(0x10 + ((ucColAddr >> 4) & 0x0F));	/* 设置列地址的高地址 */
        OLED_WrDat(ucValue);
    }
}



/*
*********************************************************************************************************
*	函 数 名: OLED_GetPixel
*	功能说明: 读取1个像素
*	形    参:
*			_usX,_usY : 像素坐标
*	返 回 值: 颜色值 (0, 1)
*********************************************************************************************************
*/
uint8_t OLED_GetPixel(uint16_t _usX, uint16_t _usY)
{
    uint8_t ucValue;
    uint8_t ucPageAddr;
    uint8_t ucColAddr;

    ucPageAddr = _usY / 8;
    ucColAddr = _usX;

    ucValue = s_ucGRAM[ucPageAddr][ucColAddr];
    if(ucValue & (_usY % 8))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}


/*
*********************************************************************************************************
*	函 数 名: OLED_DrawLine
*	功能说明: 采用 Bresenham 算法，在2点间画一条直线。
*	形    参:
*			_usX1, _usY1 ：起始点坐标
*			_usX2, _usY2 ：终止点Y坐标
*			_ucColor     ：颜色
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_DrawLine(uint16_t _usX1, uint16_t _usY1, uint16_t _usX2, uint16_t _usY2, uint8_t _ucColor)
{
    int32_t dx, dy ;
    int32_t tx, ty ;
    int32_t inc1, inc2 ;
    int32_t d, iTag ;
    int32_t x, y ;

    /* 采用 Bresenham 算法，在2点间画一条直线 */

    OLED_PutPixel(_usX1, _usY1, _ucColor);

    /* 如果两点重合，结束后面的动作。*/
    if(_usX1 == _usX2 && _usY1 == _usY2)
    {
        return;
    }

    iTag = 0 ;
    /* dx = abs ( _usX2 - _usX1 ); */
    if(_usX2 >= _usX1)
    {
        dx = _usX2 - _usX1;
    }
    else
    {
        dx = _usX1 - _usX2;
    }

    /* dy = abs ( _usY2 - _usY1 ); */
    if(_usY2 >= _usY1)
    {
        dy = _usY2 - _usY1;
    }
    else
    {
        dy = _usY1 - _usY2;
    }

    if(dx < dy)      /*如果dy为计长方向，则交换纵横坐标。*/
    {
        uint16_t temp;

        iTag = 1 ;
        temp = _usX1;
        _usX1 = _usY1;
        _usY1 = temp;
        temp = _usX2;
        _usX2 = _usY2;
        _usY2 = temp;
        temp = dx;
        dx = dy;
        dy = temp;
    }
    tx = _usX2 > _usX1 ? 1 : -1 ;    /* 确定是增1还是减1 */
    ty = _usY2 > _usY1 ? 1 : -1 ;
    x = _usX1 ;
    y = _usY1 ;
    inc1 = 2 * dy ;
    inc2 = 2 * (dy - dx);
    d = inc1 - dx ;
    while(x != _usX2)        /* 循环画点 */
    {
        if(d < 0)
        {
            d += inc1 ;
        }
        else
        {
            y += ty ;
            d += inc2 ;
        }
        if(iTag)
        {
            OLED_PutPixel(y, x, _ucColor) ;
        }
        else
        {
            OLED_PutPixel(x, y, _ucColor) ;
        }
        x += tx ;
    }
}



/*
*********************************************************************************************************
*	函 数 名: OLED_DrawPoints
*	功能说明: 采用 Bresenham 算法，绘制一组点，并将这些点连接起来。可用于波形显示。
*	形    参:
*			x, y     ：坐标数组
*			_ucColor ：颜色
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_DrawPoints(uint16_t* x, uint16_t* y, uint16_t _usSize, uint8_t _ucColor)
{
    uint16_t i;

    for(i = 0 ; i < _usSize - 1; i++)
    {
        OLED_DrawLine(x[i], y[i], x[i + 1], y[i + 1], _ucColor);
    }
}
/*
*********************************************************************************************************
*	函 数 名: OLED_DrawRect
*	功能说明: 绘制矩形。
*	形    参:
*			_usX,_usY：矩形左上角的坐标
*			_usHeight ：矩形的高度
*			_usWidth  ：矩形的宽度
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_DrawRect(uint16_t _usX, uint16_t _usY, uint8_t _usHeight, uint16_t _usWidth, uint8_t _ucColor)
{
    /*
     ---------------->---
    |(_usX，_usY)        |
    V                    V  _usHeight
    |                    |
     ---------------->---
    	  _usWidth
    */

    OLED_DrawLine(_usX, _usY, _usX + _usWidth - 1, _usY, _ucColor);	/* 顶 */
    OLED_DrawLine(_usX, _usY + _usHeight - 1, _usX + _usWidth - 1, _usY + _usHeight - 1, _ucColor);	/* 底 */

    OLED_DrawLine(_usX, _usY, _usX, _usY + _usHeight - 1, _ucColor);	/* 左 */
    OLED_DrawLine(_usX + _usWidth - 1, _usY, _usX + _usWidth - 1, _usY + _usHeight, _ucColor);	/* 右 */
}


/*
*********************************************************************************************************
*	函 数 名: OLED_DrawCircle
*	功能说明: 绘制一个圆，笔宽为1个像素
*	形    参:
*			_usX,_usY  ：圆心的坐标
*			_usRadius  ：圆的半径
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_DrawCircle(uint16_t _usX, uint16_t _usY, uint16_t _usRadius, uint8_t _ucColor)
{
    int32_t  D;			/* Decision Variable */
    uint32_t  CurX;		/* 当前 X 值 */
    uint32_t  CurY;		/* 当前 Y 值 */

    D = 3 - (_usRadius << 1);
    CurX = 0;
    CurY = _usRadius;

    while(CurX <= CurY)
    {
        OLED_PutPixel(_usX + CurX, _usY + CurY, _ucColor);
        OLED_PutPixel(_usX + CurX, _usY - CurY, _ucColor);
        OLED_PutPixel(_usX - CurX, _usY + CurY, _ucColor);
        OLED_PutPixel(_usX - CurX, _usY - CurY, _ucColor);
        OLED_PutPixel(_usX + CurY, _usY + CurX, _ucColor);
        OLED_PutPixel(_usX + CurY, _usY - CurX, _ucColor);
        OLED_PutPixel(_usX - CurY, _usY + CurX, _ucColor);
        OLED_PutPixel(_usX - CurY, _usY - CurX, _ucColor);

        if(D < 0)
        {
            D += (CurX << 2) + 6;
        }
        else
        {
            D += ((CurX - CurY) << 2) + 10;
            CurY--;
        }
        CurX++;
    }
}

/*
*********************************************************************************************************
*	函 数 名: OLED_DrawBMP
*	功能说明: 在LCD上显示一个BMP位图，位图点阵扫描次序：从左到右，从上到下
*	形    参:
*			_usX, _usY : 图片的坐标
*			_usHeight  ：图片高度
*			_usWidth   ：图片宽度
*			_ptr       ：单色图片点阵指针，每个像素占用1个字节
*	返 回 值: 无
*********************************************************************************************************
*/
void OLED_DrawBMP(uint16_t _usX, uint16_t _usY, uint16_t _usHeight, uint16_t _usWidth, uint8_t* _ptr)
{
    uint16_t x, y;

    for(x = 0; x < _usWidth; x++)
    {
        for(y = 0; y < _usHeight; y++)
        {
            OLED_PutPixel(_usX + x, _usY + y, *_ptr);
        }
    }
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode)
{
    uint8_t temp, t, t1;
    uint8_t y0 = y;
    chr = chr - ' '; //得到偏移后的值
    for(t = 0; t < size; t++)
    {
        if(size == 12)temp = oled_asc2_1206[chr][t]; //调用1206字体
        else temp = oled_asc2_1608[chr][t];		     //调用1608字体
        for(t1 = 0; t1 < 8; t1++)
        {
            if(temp & 0x80)
            {
               OLED_PutPixel(x, y, mode);
                //OLED_PutPixel(x, y, !mode);
            }
            else
            {
                OLED_PutPixel(x, y, !mode);
                //OLED_PutPixel(x, y, mode);
            }
            temp <<= 1;
            y++;
            if((y - y0) == size)
            {
                y = y0;
                x++;
                break;
            }
        }
    }
}


//m^n函数
uint32_t oled_pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while(n--)result *= m;
    return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size)
{
    uint8_t t, temp;
    uint8_t enshow = 0;
    for(t = 0; t < len; t++)
    {
        temp = (num / oled_pow(10, len - t - 1)) % 10;
        if(enshow == 0 && t < (len - 1))
        {
            if(temp == 0)
            {
                OLED_ShowChar(x + (size / 2)*t, y, ' ', size, 1);
                continue;
            }
            else enshow = 1;

        }
        OLED_ShowChar(x + (size / 2)*t, y, temp + '0', size, 1);
    }
}
//显示字符串
//x,y:起点坐标
//*p:字符串起始地址
//用16字体
void OLED_ShowString(uint8_t x, uint8_t y, const uint8_t* p)
{
#define MAX_CHAR_POSX 122
#define MAX_CHAR_POSY 58
    while(*p != '\0')
    {
        if(x > MAX_CHAR_POSX)
        {
            x = 0;
            y += 16;
        }
        if(y > MAX_CHAR_POSY)
        {
            y = x = 0;
            OLED_ClrScr(0);
        }
        OLED_ShowChar(x, y, *p, 16, 1);
        x += 8;
        p++;
    }
}




/*********************OLED初始化************************************/
void OLED_Init(void)
{
    IIC_Init();
    delay_ms(200);//初始化之前的延时很重要！
    /* 模块厂家提供初始化代码 */
    OLED_WrCmd(0xAE);	/* 关闭OLED面板显示(休眠) */
    OLED_WrCmd(0x00);	/* 设置列地址低4bit */
    OLED_WrCmd(0x10);	/* 设置列地址高4bit */
    OLED_WrCmd(0x40);	/* 设置起始行地址（低5bit 0-63）， 硬件相关*/

    OLED_WrCmd(0x81);	/* 设置对比度命令(双字节命令），第1个字节是命令，第2个字节是对比度参数0-255 */
    OLED_WrCmd(0xCF);	/* 设置对比度参数,缺省CF */

#ifdef DIR_NORMAL
    OLED_WrCmd(0xA0);	/* A0 ：列地址0映射到SEG0; A1 ：列地址127映射到SEG0 */
    OLED_WrCmd(0xC0);	/* C0 ：正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
#endif

#ifdef DIR_180
    OLED_WrCmd(0xA1);	/* A0 ：列地址0映射到SEG0; A1 ：列地址127映射到SEG0 */
    OLED_WrCmd(0xC8);	/* C0 ：正常扫描,从COM0到COM63;  C8 : 反向扫描, 从 COM63至 COM0 */
#endif

    OLED_WrCmd(0xA6);	/* A6 : 设置正常显示模式; A7 : 设置为反显模式 */

    OLED_WrCmd(0xA8);	/* 设置COM路数 */
    OLED_WrCmd(0x3F);	/* 1 ->（63+1）路 */

    OLED_WrCmd(0xD3);	/* 设置显示偏移（双字节命令）*/
    OLED_WrCmd(0x00);	/* 无偏移 */

    OLED_WrCmd(0xD5);	/* 设置显示时钟分频系数/振荡频率 */
    OLED_WrCmd(0x80);	/* 设置分频系数,高4bit是分频系数，低4bit是振荡频率 */

    OLED_WrCmd(0xD9);	/* 设置预充电周期 */
    OLED_WrCmd(0xF1);	/* [3:0],PHASE 1; [7:4],PHASE 2; */

    OLED_WrCmd(0xDA);	/* 设置COM脚硬件接线方式 */
    OLED_WrCmd(0x12);

    OLED_WrCmd(0xDB);	/* 设置 vcomh 电压倍率 */
    OLED_WrCmd(0x40);	/* [6:4] 000 = 0.65 x VCC; 0.77 x VCC (RESET); 0.83 x VCC  */

    OLED_WrCmd(0x8D);	/* 设置充电泵（和下个命令结合使用） */
    OLED_WrCmd(0x14);	/* 0x14 使能充电泵， 0x10 是关闭 */
    OLED_WrCmd(0xAF);	/* 打开OLED面板 */
    OLED_ClrScr(0X00);
}
/**********************************OLED 驱动*************************************/


/********************************End of File************************************/